package cn.seaboot.admin.api.model;

import cn.seaboot.admin.api.bean.ApiMapping;
import cn.seaboot.admin.api.bean.ApiModel;
import cn.seaboot.admin.api.bean.ApiModelField;
import cn.seaboot.admin.api.bean.ApiModelRule;
import cn.seaboot.admin.api.service.ApiMappingService;
import cn.seaboot.admin.api.service.ApiModelFieldService;
import cn.seaboot.admin.api.service.ApiModelRuleService;
import cn.seaboot.admin.api.service.ApiModelService;
import cn.seaboot.commons.core.CommonUtils;
import cn.seaboot.commons.reflect.FieldAccess;
import cn.seaboot.commons.reflect.ObjectField;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.List;

/**
 * 扫描对象模型
 *
 * @author Mr.css
 * @version 2022-04-18 11:41
 */
@Component
public class ApiModelManager {
    private final Logger logger = LoggerFactory.getLogger(ApiModelManager.class);

    @Resource
    private ApiMappingService apiMappingService;

    @Resource
    private ApiModelService apiModelService;

    @Resource
    private ApiModelFieldService apiModelFieldService;

    @Resource
    private ModelScanner modelScanner;

    /**
     * 扫描 mapping 返回值的对象模型
     */
    public void scanMappingModel(String projectId) {
        List<ApiMapping> list = apiMappingService.queryByProjectId(projectId);
        for (ApiMapping mapping : list) {
            String model = mapping.getResponseClass();
            if (model.startsWith("cn.seaboot")) {
                try {
                    Class<?> clazz = Class.forName(model);
                    this.scanModel(projectId, clazz);
                } catch (Exception e) {
                    logger.error("scan model failed: " + model, e);
                }
            }

            model = mapping.getResponseGeneric();
            if (CommonUtils.isNotEmpty(model) && model.startsWith("cn.seaboot")) {
                try {
                    Class<?> clazz = Class.forName(model);
                    this.scanModel(projectId, clazz);
                } catch (Exception e) {
                    logger.error("scan model failed: " + model, e);
                }
            }
        }
    }

    /**
     * 清理所有数据
     *
     * @param projectId 工程ID
     */
    public void cleanModel(String projectId) {
        apiModelService.deleteByProjectId(projectId);
        apiModelFieldService.deleteByProjectId(projectId);
    }

    /**
     * 扫描一个对象，因为用户允许微调，不允许覆盖原有数据，除非删除历史数据
     *
     * @param projectId 工程ID
     */
    public void scanModel(String projectId, Class<?> clazz) {
        String name = clazz.getName();
        ApiModel m = apiModelService.queryById(projectId, name);
        if (m != null) {
            logger.debug("already scan model: {}", clazz);
        } else {
            FieldAccess fieldAccess = FieldAccess.create(clazz);

            // class
            ApiModel model = modelScanner.scanApiModel(projectId, clazz);
            if (model != null) {
                apiModelService.insert(model);

                for (ObjectField field : fieldAccess.getFields()) {
                    // field
                    ApiModelField modelField = modelScanner.scanApiModelField(model, field);
                    if(modelField != null){
                        apiModelFieldService.insert(modelField);
                    }
                }
            } else {
                logger.debug("ignore model: {}", clazz);
            }
        }
    }
}
